#include <stdint.h>
#include <stddef.h>

#include "driver_gpio.h"
#include "fr30xx.h"
#include "app_task.h"
#include "fr_device_pmu_io.h"
#include "fr_device_encode.h"
#include "app_lvgl.h"

/* FreeRTOS kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"

//extern uint8_t key_code;

#define  ENCODE_FILO_LEN		16

static uint8_t encode_bit_status = 0;
static uint8_t encode_bit_code = 0;

__attribute__((section("dram_section"))) encode_type_t encode_table_filo[ENCODE_FILO_LEN];
__attribute__((section("dram_section"))) uint8_t encode_table_key[ENCODE_FILO_LEN];

uint8_t key_release_flag = 0;

const uint8_t encode_table_value[8][5] =
{
	{0x01, 0x00, 0x02, 0x03, 0x01},
	{0x02, 0x03, 0x01, 0x00, 0x01},
	{0x03, 0x01, 0x00, 0x02, 0x01},
	{0x00, 0x02, 0x03, 0x01, 0x01},


	{0x02, 0x00, 0x01, 0x03, 0x02},
	{0x01, 0x03, 0x02, 0x00, 0x02},
	{0x03, 0x02, 0x00, 0x01, 0x02},
	{0x00, 0x01, 0x03, 0x02, 0x02},

};

uint32_t encode_last_time;
static uint32_t get_encode_basetime(void)
{
	uint32_t cur_base_time = portGET_RUN_TIME_COUNTER_VALUE();
    uint32_t diff;
    if(cur_base_time >= encode_last_time)
        diff = cur_base_time - encode_last_time;
    else
        diff = (((uint32_t)0xFFFFFFFF)  - encode_last_time) + cur_base_time + 1;

	encode_last_time = cur_base_time;
	return diff;
}


uint32_t encode_release_last_time;
static uint32_t get_encode_release_basetime(void)
{
	uint32_t cur_base_time = portGET_RUN_TIME_COUNTER_VALUE();
    uint32_t diff;
    if(cur_base_time >= encode_release_last_time)
        diff = cur_base_time - encode_release_last_time;
    else
        diff = (((uint32_t)0xFFFFFFFF)  - encode_release_last_time) + cur_base_time + 1;

	return diff;
}


void clear_encode_fifo(void)
{
	encode_last_time = portGET_RUN_TIME_COUNTER_VALUE();
	memset(encode_table_filo,0,ENCODE_FILO_LEN*2);
}


void encode_push_key(uint8_t key_value)
{
	uint8_t i;
	uint32_t time;

	time = get_encode_basetime();
	if(time <= 3)
	{
		time += encode_table_filo[0].time;
		if(time > 0xff)
			time = 0xff;
		encode_table_filo[0].time = time;
		encode_table_filo[0].keyvalue = key_value;
		// printf("fiter");
	}
	else
	{
		for(i = ENCODE_FILO_LEN - 1; i > 0; i -- )
		{
			encode_table_filo[i] = encode_table_filo[i - 1];
		}
		encode_table_filo[0].keyvalue = key_value;


		if(time > 255)
		{
			encode_table_filo[0].time = 0xff;
			// printf("\n");
			// printf("\n");
			// printf("\n");
			// printf("\n");
			// printf("\n");
			// printf("\n");
		}
		else
			encode_table_filo[0].time = time;

	}
	// printf("keyvlue:");
	// for(i = 0; i < 15; i ++ )
	// {
	// 	printf("%d/", encode_table_filo[i].keyvalue);
	// 	printf("%d ", encode_table_filo[i].time);
	// }
	// printf("\n");

}


uint8_t get_encode_start(void)
{
	uint8_t i = 0;
	while(i < ENCODE_FILO_LEN)
	{
		if(encode_table_filo[i].time == 0xff)
		{
			i ++;
			break;
		}
		i ++;
	}
	return i;
}


void encode_event_handle(uint8_t key_value)
{

	uint8_t len;
	uint8_t start;
	uint8_t i,j;

	// if (get_charte_state())
	// 	return;
	// if (system_enter_music_flag)
	// 	return;

	//printf("value %d\n", key_value);

	start = get_encode_start();
	len = start; 
	for(i = 0; i < len; i++)
	{
		encode_table_key[i] = encode_table_filo[start - 1].keyvalue;
		start --;
	}

	if(len > 4)
	{
		j = 0;
		while(j < (len-4))
		{
			i = 0;
			while(i < 8)
			{
				if(memcmp(&encode_table_value[i][0],encode_table_key+j,4) == 0)
				{
					//if(!key_release_flag)
					{
						//os_timer_stop(&encode_release_timer);
						encode_bit_code = encode_table_value[i][4];
						//printf("code %d \n",encode_bit_code);
						key_release_flag = 1;
						
//						if(!gui_task_resume())
//						{
//							encode_release_last_time = portGET_RUN_TIME_COUNTER_VALUE();
//							encode_bit_code |= 0x80;
//							gui_task_msg_send(ENCODE_KEY_EVT,(void *)&encode_bit_code,1,NULL,0,NULL);
//						}
						return;
					}
				}
				i ++;
			}

			j++;
		}

	}
	else if((len >= 2) && (len <= 4))
	{
		i = 0;
		while(i < 8)
		{
			if(memcmp(&encode_table_value[i][0],encode_table_key,len) == 0)
			{
				//if(!key_release_flag)
				{
					//os_timer_stop(&encode_release_timer);
					encode_bit_code = encode_table_value[i][4];
					//printf("code %d \n",encode_bit_code);
					key_release_flag = 1;

//					if(!gui_task_resume())
//					{
//						encode_release_last_time = portGET_RUN_TIME_COUNTER_VALUE();
//						encode_bit_code |= 0x80;
//						gui_task_msg_send(ENCODE_KEY_EVT,(void *)&encode_bit_code,1,NULL,0,NULL);
//					}
					return;
				}
			}
			i ++;
		}
	}

}

bool encode_key_release(void)
{
	if(get_encode_release_basetime() > 10)
	{
//		key_code = 0;
		return true;
	}
	return false;
}



void encode_toggle_detected(uint8_t curr_encode)
{

	//printf("encode %d \n",curr_encode);

	if(encode_bit_status != curr_encode)
	{
		encode_bit_status = curr_encode;
		encode_push_key(curr_encode);

		struct app_task_event *event;
		event = app_task_event_alloc(APP_TASK_EVENT_ENCODE_TOGGLE, sizeof(uint8_t), false);
		if(event) 
		{
			memcpy(event->param, (void *)&curr_encode, sizeof(uint8_t));
			event->param_len = sizeof(uint8_t);
			app_task_event_post(event, false);
		}

	}
}




